﻿using System;
using System.Collections.Generic;
using System.Diagnostics;

namespace LightFactory
{
    /// <summary>
    /// You need to implement this class as your own factory and register its instance before using create methods of Factory<typeparamref name="T"/> clas
    /// </summary>
    public abstract class FactoryBase
    {        
        /// <summary>
        /// Register instance of FatoryBase derived class as current Factory logic
        /// </summary>
        public static void RegisterFactory(FactoryBase factory)
        {
            factory.InitFactory();
        }

        /// <summary>
        /// Override this method to provide generators registrations
        /// </summary>
        protected abstract void InitFactory();

        #region define generator methods
        /// <summary>
        /// Define instantiation logic for type T
        /// </summary>
        protected void Define<T>(Func<T> generator)
        {
            GeneratorWrapper<T>.generator = generator;
        }

        /// <summary>
        /// Define instantiation logic for type T
        /// </summary>
        protected void Define<T, TParam1>(Func<TParam1, T> generator)
        {
            GeneratorWrapper1<T, TParam1>.generator = generator;
        }

        /// <summary>
        /// Define instantiation logic for type T
        /// </summary>
        protected void Define<T, TParam1, TParam2>(Func<TParam1, TParam2, T> generator)
        {
            GeneratorWrapper2<T, TParam1, TParam2>.generator = generator;
        }

        /// <summary>
        /// Define instantiation logic for type T
        /// </summary>
        protected void Define<T, TParam1, TParam2, TParam3>(Func<TParam1, TParam2, TParam3, T> generator)
        {
            GeneratorWrapper3<T, TParam1, TParam2, TParam3>.generator = generator;
        }

        /// <summary>
        /// Define instantiation logic for type T
        /// </summary>
        protected void Define<T, TParam1, TParam2, TParam3, TParam4>(Func<TParam1, TParam2, TParam3, TParam4, T> generator)
        {
            GeneratorWrapper4<T, TParam1, TParam2, TParam3, TParam4>.generator = generator;
        }
        #endregion

        #region generator classes
        internal class GeneratorWrapper<T>
        {
            public static Func<T> generator;
            public static T SingleInstance { get; set; }
        }
        internal class GeneratorWrapper1<T, TParam1>
        {
            public static Func<TParam1, T> generator;
        }
        internal class GeneratorWrapper2<T, TParam1, TParam2>
        {
            public static Func<TParam1, TParam2, T> generator;
        }
        internal class GeneratorWrapper3<T, TParam1, TParam2, TParam3>
        {
            public static Func<TParam1, TParam2, TParam3, T> generator;
        }
        internal class GeneratorWrapper4<T, TParam1, TParam2, TParam3, TParam4>
        {
            public static Func<TParam1, TParam2, TParam3, TParam4, T> generator;
        }
        #endregion
    }
}